/**
 * 
 */
package com.demo2do.core.redis;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;

import redis.clients.jedis.JedisPool;

import com.demo2do.core.utils.JsonUtils;


/**
 * @author Downpour
 */
public class GenericRedisSupport {

	private JedisTemplate jedisTemplate;
	
	@Value("#{redis['namespace']}")
	private String namespace;
	
	/**
	 * 
	 * @param jedisPool
	 */
	public void setJedisPool(JedisPool jedisPool) {
		this.jedisTemplate = new JedisTemplate(jedisPool);
	}
	
	/**
	 * add new string into set
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public Boolean addMembersToSet(String key, String... members) {
		return jedisTemplate.sadd(namespace + ":" + key, members);
	}
	
	/**
	 * add new object into set, every member needs to be serialized to string
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public Boolean addMembersToSet(String key, Object... members) {
		String[] omembers = new String[members.length];
		for(int i = 0; i < members.length; i++) {
			omembers[i] = JsonUtils.toJsonString(members[i]);
		}
		return this.addMembersToSet(key, omembers);
	}
	
	/**
	 * add new string into sorted set
	 * 
	 * @param key
	 * @param member
	 * @param score
	 * @return
	 */
	public Boolean addMemberToSortedSet(String key, String member, double score) {
		return jedisTemplate.zadd(namespace + ":" + key, member, score);
	}
	
	/**
	 * add new object into sorted set
	 * 
	 * @param key
	 * @param member
	 * @param score
	 * @return
	 */
	public Boolean addMemberToSortedSet(String key, Object member, double score) {
		return jedisTemplate.zadd(namespace + ":" + key, JsonUtils.toJsonString(member), score);
	}
	
	/**
	 * get all the members as a set of string according to a key
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getMembersForSet(String key) {
		return jedisTemplate.smembers(namespace + ":" + key);
	}
	
	/**
	 * get all the members as a set of object according to a key
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public <T> Set<T> getMembersForSet(String key, Class<T> clazz) {
		Set<String> smembers = this.getMembersForSet(key);
		Set<T> omembers = new HashSet<T>(smembers.size());
		for(String member : smembers) {
			omembers.add(JsonUtils.parse(member, clazz));
		}
		return omembers;
	}
	
	/**
	 * get all the members as a set of string according to a key and order asce
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getMembersForSortedSet(String key) {
		return jedisTemplate.zrange(namespace + ":" + key, 0, -1);
	}
	
	/**
	 * get all the members as a set of object according to a key and order asce
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public <T> Set<T> getMembersForSortedSet(String key, Class<T> clazz) {
		Set<String> smembers = this.getMembersForSortedSet(key);
		Set<T> omembers = new LinkedHashSet<T>(smembers.size());
		for(String member : smembers) {
			omembers.add(JsonUtils.parse(member, clazz));
		}
		return omembers;
	}
	
	/**
	 * get all the members as a set of string according to a key and order desc 
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getReverseMembersForSortedSet(String key) {
		return jedisTemplate.zrevrange(namespace + ":" + key, 0, -1);
	}
	
	/**
	 * get all the members as a set of object according to a key and order desc
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public <T> Set<T> getReverseMembersForSortedSet(String key, Class<T> clazz) {
		Set<String> smembers = this.getReverseMembersForSortedSet(key);
		Set<T> omembers = new LinkedHashSet<T>(smembers.size());
		for(String member : smembers) {
			omembers.add(JsonUtils.parse(member, clazz));
		}
		return omembers;
	}
	
	/**
	 * get the size of set according to a key
	 * 
	 * @param key
	 * @return
	 */
	public Long getSizeOfSet(String key) {
		return jedisTemplate.scard(namespace + ":" + key);
	}
	
	/**
	 * get the size of sorted set according to a key
	 * 
	 * @param key
	 * @return
	 */
	public Long getSizeOfSortedSet(String key) {
		return jedisTemplate.zcard(namespace + ":" + key);
	}

	/**
	 * @param key
	 * @return
	 */
	public int getAsInt(String key) {
		Integer result = jedisTemplate.getAsInt(namespace + ":" + key);
		return result == null ? 0 : result;
	}

	/**
	 * @param key
	 * @return
	 */
	public String getValue(String key) {
		return jedisTemplate.get(key);
	}
	
	/**
	 * remove string from set according to key 
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public boolean removeMembersFromSet(String key, String... members) {
		return jedisTemplate.srem(namespace + ":" + key, members);
	}
	
	/**
	 * remove object from set according to key
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public boolean removeMembersFromSet(String key, Object... members) {
		String[] omembers = new String[members.length];
		for(int i = 0; i < members.length; i++) {
			omembers[i] = JsonUtils.toJsonString(members[i]);
		}
		return this.removeMembersFromSet(key, omembers);
	}
	
	/**
	 * remove string from sorted set according to key
	 * 
	 * @param key
	 * @param member
	 * @return
	 */
	public boolean reomveMemberFromSortedSet(String key, String member) {
		return jedisTemplate.zrem(namespace + ":" + key, member);
	}
	
	/**
	 * remove object from sorted set according to key
	 * 
	 * @param key
	 * @param member
	 * @return
	 */
	public boolean removeMemberFromSortedSet(String key, Object member) {
		return jedisTemplate.zrem(namespace + ":" + key, JsonUtils.toJsonString(member));
	}
	
	/**
	 * expire key in give seconds time
	 * 
	 * @param key
	 * @param seconds
	 * @return
	 */
	public Long expire(String key, int seconds) {
		return jedisTemplate.expire(namespace + ":" + key, seconds);
	}
	
	/**
	 * push member to list
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public void addMembersToList(String key, String... members) {
		jedisTemplate.lpush(namespace + ":" + key, members);
	}
	
	/**
	 * push object member to list
	 * 
	 * @param key
	 * @param members
	 * @return
	 */
	public void addMembersToList(String key, Object... members) {
		String[] omembers = new String[members.length];
		for(int i = 0; i < members.length; i++) {
			omembers[i] = JsonUtils.toJsonString(members[i]);
		}
		this.addMembersToList(key, omembers);
	}

	/**
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean removeMemberFromList(String key, String value) {
		return jedisTemplate.lremOne(namespace + ":" + key, value);
	}
	
	/**
	 * trim list
	 * 
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public String trimList(String key, long start, long end) {
		return jedisTemplate.ltrim(namespace + ":" + key, start, end);
	}

	/**
	 * increase count by one
	 * 
	 * @param key
	 * @return
	 */
	public Long increaseCount(String key) {
		return jedisTemplate.incr(namespace + ":" + key);
	}

	/**
	 * @param key
	 * @return
	 */
	public Long decreaseCount(String key) {
		return jedisTemplate.decr(namespace + ":" + key);
	}
	
	/**
	 * get all members of list
	 * 
	 * @param key
	 * @return
	 */
	public List<String> getMembersForList(String key) {
		return jedisTemplate.lrange(namespace + ":" + key, 0, -1);
	}
	
	/**
	 * get all object members of list
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public <T> List<T> getMembersForList(String key, Class<T> clazz) {
		List<String> lmembers = this.getMembersForList(key);
		List<T> omembers = new ArrayList<T>();
		for(String member : lmembers) {
			omembers.add(JsonUtils.parse(member, clazz));
		}
		return omembers;
	}

}
